This section contains the following topics:
In effect, fec/fecc takes a snapshot of the state of the compilation at a particular point and writes it to a file before completing the compilation. When you recompile the same source file or another file with the same set of header files, the PCH mechanism recognizes the snapshot point, verifies that the corresponding PCH file is usable, and reads it back in.
The PCH mechanism can give you a dramatic improvement in compile-time performance. The trade-off is that PCH files may take a lot of disk space.
The PCH file contains a snapshot of all the code preceding the header stop point. The header stop point is typically the first token in the primary source file that does not belong to a preprocessing directive. The header stop point can also be specified directly by inserting a #pragma hdrstop. For example, consider the following C++ code:
#include "xxx.h" #include "yyy.h" int i;In this case, the header stop point is
int i
(the first non-preprocessor token) and the PCH file will contain a snapshot reflecting the inclusion of xxx.h and yyy.h. If the first non-preprocessor token or the #pragma hdrstop appears within a #if
block, the header stop point is the outermost enclosing #if
. For example, consider the following C++ code:
#include "xxx.h" #ifndef YYY_H #define YYY_H 1 #include "yyy.h" #endif #if TEST int i; #endifIn this case, the first token that does not belong to a preprocessing directive is again
int i
, but the header stop point is the start of the #if
block containing the int
. The PCH file reflects the inclusion of xxx.h and conditionally the definition of YYY_H and inclusion of yyy.h. The file does not contain the state produced by #if TEST
.PCH File Requirements
A PCH file is produced only if the header stop point and the code preceding it (generally the header files themselves) meet the following requirements:
// xxx.h
class A {
// xxx.C
#include "xxx.h"
int i; };
// yyy.h
static
// yyy.C
#include "yyy.h"
int i;
In this case, the header stop point is int i
, but since it is not the start of a new declaration, a PCH file is not created
#if
block or a #define
started within a header file.
#line
preprocessing directive must not have appeared.
#pragma no_pch
must not have appeared.
When a precompiled header file is produced, in addition to the snapshot of the compiler state, it contains some information that can be checked to determine under what circumstances it can be reused. This information includes the following:
#include
directives.
#include
directives.
For example, consider the following C++ code:
// a.C #include "xxx.h" ... // Start of code // b.C #include "xxx.h" ... // Start of codeWhen you compiled a.C with the -pch option, the PCH file a.pch is created. When you compile b.C (or recompile a.C), the prefix section of a.pch is read in for comparison with the current source file. If the command line options are identical and xxx.h has not been modified, fec/fecc reads in the rest of a.pch rather than opening xxx.h and processing it line by line. This establishes the state for the rest of the compilation.
It may be that more than one PCH file is applicable to a given compilation. If so, the largest (in other words, the one representing the most preprocessing directives from the primary source file) is used. For instance, consider a primary source file that begins with the following code:
#include "xxx.h" #include "yyy.h" #include "zzz.h"If one PCH file exists for xxx.h and a second for xxx.h and yyy.h, the latter will be selected (assuming both are applicable to the current compilation). After the PCH file for the first two headers is read in and the third is compiled, a new PCH file for all three headers may be created.
When a precompiled header file is created, it takes the name of the primary source file, with the suffix replaced by "pch." Unless -pch_dir is specified, the PCH file is created in the directory of the primary source file.
When a precompiled header file is created or used, a message similar to the following is issued:
Obsolete File Deletion Mechanism"test.C": creating precompiled header file "test.pch"
In automatic mode (when -pch is used), fec/fecc considers a PCH file obsolete and deletes it under the following circumstances:
Support for PCH processing is not available when multiple source files are specified in a single compilation. If the command line includes a request for precompiled header processing and specifies more than one primary source file, an error is issued and the compilation is aborted.
#pragma hdrstop
in the primary source file at a point prior to the first token that does not belong to a preprocessing directive. Thus you can specify where the set of header files subject to precompilation ends. For example,
#include "xxx.h"
#include "yyy.h"
#pragma hdrstop
#include "zzz.h"
In this case, the precompiled header file includes the processing state for xxx.h and yyy.h but not zzz.h. (This is useful if you decide that the information added by what follows the #pragma hdrstop
does not justify the creation of another PCH file.)
#pragma no_pch
to suppress the precompiled header processing for a given source file.
In general, writing out a precompiled header file doesn't cost much, even if it does not end up being used, and if it is used it almost always produces a significant speedup in compilation. The problem is that the precompiled header files can be quite large (from a minimum of about 250K bytes to several megabytes or more), and so you probably don't want many of them sitting around.
You can see that, despite the faster recompilations, precompiled header processing is not likely to be justified for an arbitrary set of files with nonuniform initial sequences of preprocessing directives. The greatest benefit occurs when a number of source files can share the same PCH file. The more sharing, the less disk space is consumed. With sharing, the disadvantage of large precompiled header files can be minimized without giving up the advantage of a significant speedup in compilation times.
To take full advantage of header file precompilation, you should reorder the #include
sections of your source files and/or group the #include
directives within a commonly used header file.
The fecc source provides an example of how this can be done. A common idiom is the following:
#include "fe_common.h" #pragma hdrstop #include ...In this example, fe_common.h pulls in (directly and indirectly) a few dozen header files. The
#pragma hdrstop
is inserted to get better sharing with fewer PCH files. The PCH file produced for fe_common.h is slightly over a megabyte in size. Another example, used by the source files involved in declaration processing, is the following:
#include "fe_common.h" #include "decl_hdrs.h" #pragma hdrstop #include ...decl_hdrs.h pulls in another dozen header files, and a second, somewhat larger, PCH file is created. In all, the fifty-odd source files of fecc share just six precompiled header files. If disk space is at a premium, you can decide to make fe_common.h pull in all the header files used. In that case, a single PCH file can be used in building fecc.
Different environments and different projects have different needs. You should, however, be aware that making the best use of the precompiled header support will require some experimentation and probably some minor changes to your source code.